//! @author Adam Emil Skoog
//! @date   2011-12-24

#include "Component.h"
#include "EventManager.h"
#include "EventReceiver.h"
#include "MouseInputEventReceiver.h"
#include "KeyInputEventReceiver.h"
#include <cassert>

namespace kedja
 {
	/**
	 * Constructor.
	 */
	Component::Component()
	:
	previousComponent  (NULL),
	nextComponent      (NULL),
	parentComponent    (NULL),
	firstChildComponent(NULL),
	layerable          (false),
	layerablePermitted (false)
	 {
	 }

	/**
	 * Creates the main component. This must be called before it
	 * is possible to retrieve it, and may only be called once
	 * until the component has been destroyed again, which should
	 * at least be done at the end of the program, to avoid the
	 * possiblity of memory being leaked.
	 */
	void Component::createMainComponent()
	 {
		// There may be no previous component.
		assert(!static_cast<bool>(mainComponent));

		if (!mainComponent)
		 {
			mainComponent = new Component;
			eventManager  = new EventManager;
			EventReceiver::initialise();
			MouseInputEventReceiver::initialise();
			KeyInputEventReceiver::initialise();
		 }
	 }

	/**
	 * Returns the main component of the program. It must be
	 * created first and should be properly disposed of at the
	 * end of the program, to avoid the possiblity of memory
	 * being leaked.
	 *
	 * @return A pointer to the main component.
	 */
	Component *const Component::getMainComponent()
	 {
		// The main component must be created first.
		assert(static_cast<bool>(mainComponent));
		return mainComponent;
	 }

	/**
	 * Destroys the main component. Must be called before the
	 * program ends, or the data might leak.
	 */
	void Component::destroyMainComponent()
	 {
		// There must be a component to delete.
		assert(static_cast<bool>(mainComponent));

		if (mainComponent)
		 {
			KeyInputEventReceiver::deinitialise();
			MouseInputEventReceiver::deinitialise();
			EventReceiver::deinitialise();

			delete eventManager;
			delete mainComponent;

			eventManager  = NULL;
			mainComponent = NULL;
		 }
	 }

	/**
	 * Updates the component system. This should be called every
	 * frame, and requires a main component to have been created
	 * first.
	 */
	void Component::updateComponentSystem()
	 {
		// There must be a component to handle.
		assert(static_cast<bool>(mainComponent));

		if (mainComponent)
		 {
			eventManager->beginFrame();
			mainComponent->draw();
			eventManager->endFrame();
		 }
	 }

	/**
	 * Returns the event manager. The main component must have been created.
	 *
	 * @return The event manager.
	 */
	EventManager *const Component::getEventManager()
	 {
		// There must be an event manager first.
		assert(static_cast<bool>(eventManager));
		return eventManager;
	 }

	/**
	 * Removes the child component with the specific address, if it exists, and then
	 * deallocates it from memory completely.
	 *
	 * @param component A pointer to the component to unlink.
	 * @return Whether the component existed and thus was removed.
	 */
	bool Component::destroyComponent(Component *const component)
	 {
		// The component must not be NULL.
		assert(static_cast<bool>(component));

		if (component)
		 {
			for (Component *i(firstChild()); i; i = i->next())
			 {
				if (i == component)
				 {
					i->previous()->unlinkNext();
					return true;
				 }
			 }
		 }

		return false;
	 }

	/**
	 * Returns the previous sibling component.
	 *
	 * @return A pointer to the previous sibling, or NULL, if there is none.
	 */
	Component *const Component::previous() const
	 {
		return previousComponent;
	 }

	/**
	 * Returns the next sibling component.
	 *
	 * @return A pointer to the next sibling, or NULL, if there is none.
	 */
	Component *const Component::next() const
	 {
		return nextComponent;
	 }

	/**
	 * Returns the parent component.
	 *
	 * @return A pointer to the parent, or NULL, if there is none.
	 */
	Component *const Component::parent() const
	 {
		return parentComponent;
	 }

	/**
	 * Returns the first child component.
	 *
	 * @return A pointer to the first child, or NULL, if there is none.
	 */
	Component *const Component::firstChild() const
	 {
		return firstChildComponent;
	 }

	/**
	 * Registers an event receiver with the component. It will not be deallocated
	 * automatically, and removing it will not deallocate it, since the same
	 * event receiver could, and preferably often should, be added to several
	 * components not to waste memory.
	 * <br /><br />
	 *
	 * The specified class must be a child of EventReceiver, and must have
	 * a default constructor with a Component pointer as its argument.
	 *
	 * @param receiever The receiver to register.
	 * @return The new event receiver.
	 */
	Component &Component::registerEventReceiver(EventReceiver *const receiver)
	 {
		// Allocate the new component.
		eventReceivers.push_back(receiver);
		receiver->registerParent(this);
		return *this;
	 }

	/**
	 * Deregisters the event receiver from the specific address, if it exists. 
	 *
	 * @param receiver A pointer to the receiver to remove.
	 * @return Whether the receiver existed and thus was removed.
	 */
	bool Component::deregisterEventReceiver(EventReceiver *const receiver)
	 {
		// The component must not be NULL.
		assert(static_cast<bool>(receiver));

		if (receiver)
		 {
			for (unsigned i(0); i < eventReceivers.size(); ++ i)
			 {
				if (eventReceivers[i] == receiver)
				 {
					eventReceivers.erase(eventReceivers.begin() + i);
					receiver->deregisterParent(this);
					return true;
				 }
			 }
		 }

		return false;
	 }

	/**
	 * Sets whether the component should be layerable. This setting can
	 * only be change if this is specified in the class itself, and if
	 * it is not permitted, an assertion will be thrown.
	 * <br /><br />
	 *
	 * By default, this is set to false.
	 *
	 * @param layerable Whether to set layerable. Defaults to true if omitted.
	 * @return The modified component object.
	 */
	Component &Component::setLayerable(const bool &layerable)
	 {
		// The setting must be enabled.
		assert(layerableFlagModificationIsPermitted());

		if (layerableFlagModificationIsPermitted() && isLayerable() != layerable)
			this->layerable = layerable;

		return *this;
	 }

	/**
	 * Returns whether the component is layerable.
	 *
	 * @return Whether the component is layerable.
	 */
	const bool &Component::isLayerable() const
	 {
		return layerable;
	 }

	/**
	 * Sets whether the component should be layerable. This is protected and can
	 * only be set by the object itself. It is meant to be set in the constructor
	 * of a child class of which the possibility to modify this setting should be
	 * enabled. The same goes for enabling layerability without necessarily
	 * enabling the user to modify the setting after that, in which case this
	 * should also be set in the constructor.
	 * <br /><br />
	 *
	 * By default, this is set to false.
	 *
	 * @param permit Whether to enable the setting. Defaults to true if omitted.
	 * @return The modified component object.
	 */
	Component &Component::setLayerableFlagModificationPermitted(const bool &permit)
	 {
		if (layerableFlagModificationIsPermitted() != permit)
			this->layerablePermitted = permit;

		return *this;
	 }

	/**
	 * Returns whether it is permitted for the user to set the layerability flag
	 * of this component.
	 *
	 * @return Whether layerability modification is permitted.
	 */
	const bool &Component::layerableFlagModificationIsPermitted() const
	 {
		return layerablePermitted;
	 }

	/**
	 * Links the specified component as the next one.
	 *
	 * @param component Component to link.
	 */
	void Component::link(Component *const component)
	 {
		// If there is a following component, properly insert the new one.
		if (next())
		 {
			next()->previousComponent = component;
			component->nextComponent  = next();
		 }

		// Establish the connection.
		nextComponent                = component;
		component->previousComponent = this;
	 }

	/**
	 * Renders the component. This must be implemented for each child.
	 */
	void Component::render()
	 {
		// Does not do anything in the base class.
	 }

	/**
	 * Unlinks and deallocates the next component.
	 */
	void Component::unlinkNext()
	 {
		// There must be a next component.
		assert(static_cast<bool>(next()));

		if (next())
		 {
			Component *const oldNext(next());

			if (next()->next())
			 {
				next()->next()->previousComponent = this;
				nextComponent = next()->next();
			 }
			else
				nextComponent = NULL;

			delete oldNext;
		 }
	 }

	/**
	 * Returns the last sibling in the chain.
	 *
	 * @return The last sibling, or NULL, if this is the last component.
	 */
	Component *const Component::getLastSibling() const
	 {
		for (Component *i(next()); i; i = i->next())
			if (!i->next())
				return i;

		return const_cast<Component *const>(this);
	 }

	/**
	 * Draws the component.
	 */
	void Component::draw()
	 {
		render();

		// Draw the child components.
		for (Component *i(firstChild()); i; i = i->next())
			i->draw();
	 }

	/**
	 * Destructor. Will also destroy the children of the component, and their children
	 * in turn, recursively. Thus it is only necessary to destroy the main component to
	 * clean up all components in the entire program.
	 */
	Component::~Component()
	 {
		for (Component *i(firstChild()); i; i = i->next())
			delete i;
	 }

	// Define static variables.
	Component    *Component::mainComponent = NULL;
	EventManager *Component::eventManager  = NULL;
 }
